//definicion librerias
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include "contexto.h"
#include "contContextos.h"
#include <limits.h>
#include <time.h> 
//definicion constantes
#define tope USHRT_MAX
#define unidad 1


/* ******************************************************************
 *                      FUNCIONES AUXILIARES
 * *****************************************************************/

//funcion que devuelve un string de tipo size aleatorio.
//fuente: http://www.tek-tips.com/viewthread.cfm?qid=1259127
char *rand_str(char *dst, int size)
{
   static const char text[] = "abcdefghijklmnopqrstuvwxyz"
                              "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
   int i, len = rand() % (size - 1);
   for ( i = 0; i < len; ++i )
   {
      dst[i] = text[rand() % (sizeof text - 1)];
   }
   dst[i] = '\0';
   return dst;
}
/* Función auxiliar para imprimir si estuvo OK o no. */
void print_test(char* name, bool result)
{
    printf("%s: %s\n", name, result? "OK" : "ERROR");
}

/* ******************************************************************
 *                        PRUEBAS UNITARIAS
 * *****************************************************************/

void prueba_crear_palabra_vacio()
{
	palabra_t* unapalabra = palabra_crear("");
	print_test("Crear palabra sin caracteres =null",unapalabra == NULL);
	print_test("Obtener frecuencia palabra sin caracteres = 0" ,obtener_frecuencia(unapalabra) == 0);
	print_test("suamr frecuencia palabra sin caracteres = false" ,sumar_frecuencia(unapalabra) == false);
	print_test("restar frecuencia palabra sin caracteres = false" ,restar_frecuencia(unapalabra,unidad) == false);
	
	
	unapalabra = palabra_crear(NULL);
	print_test("Crear palabra vacia",unapalabra == NULL);
	print_test("Obtener frecuencia palabra vacia = 0" ,obtener_frecuencia(unapalabra) == 0);
	print_test("sumar frecuencia palabra vacia = false" ,sumar_frecuencia(unapalabra) == false);
	print_test("restar frecuencia palabra vacia = false" ,restar_frecuencia(unapalabra,unidad) == false);
	

}
void prueba_crear_palabra_correcta(){

	palabra_t* unapalabra = palabra_crear("palabra");

	print_test("Crear palabra correcta != null",unapalabra != NULL);
	print_test("Obtener frecuencia palabra correcta = 1" ,obtener_frecuencia(unapalabra) == 1);
	print_test("sumar frecuencia palabra correcta = true" ,sumar_frecuencia(unapalabra) == true);
	print_test("Obtener frecuencia palabra correcta = 2 " ,obtener_frecuencia(unapalabra) == 2);
	print_test("restar 1 frecuencia palabra correcta = true" ,restar_frecuencia(unapalabra,unidad) == true);
	print_test("Obtener frecuencia palabra correcta = 1" ,obtener_frecuencia(unapalabra) == 1);
	
	//pruebo restar frecuencias y no poder obtener frecuencias <0
	print_test("restar frecuencia palabra correcta = true" ,restar_frecuencia(unapalabra,unidad) == true);
	print_test("Obtener frecuencia palabra correcta = 0" ,obtener_frecuencia(unapalabra) == 0);
	print_test("resto frecuencia palabra correcta con frecuencia 0 = false" ,restar_frecuencia(unapalabra,unidad) == false);
	print_test("Obtener frecuencia palabra correcta luego de disminuir frecuencia 0 = 0" ,obtener_frecuencia(unapalabra) == 0);

	print_test("resto frecuencia  mayor que 1 a palabra correcta con frecuencia 0 = false" ,restar_frecuencia(unapalabra,7*unidad) == false);
	print_test("Obtener frecuencia palabra correcta luego de disminuir frecuencia 0 = 0" ,obtener_frecuencia(unapalabra) == 0);

	//pruebo frecuencias frecuencias
	bool res = sumar_frecuencia(unapalabra) == true;
	res = sumar_frecuencia(unapalabra) == true;
	res = sumar_frecuencia(unapalabra) == true;
	res = sumar_frecuencia(unapalabra) == true;
	res = sumar_frecuencia(unapalabra) == true;
	res = sumar_frecuencia(unapalabra) == true;
	if (res){
		print_test("Aumentar la frecuencia  hasta 6 = 6" ,unidad == unidad);
	}else{
		print_test("Aumentar la frecuencia  hasta 6 = 6" ,unidad != unidad);		
	}
	print_test("Obtener la frecuencia en palabra correcta 6 = 6" ,obtener_frecuencia(unapalabra) == (6*unidad));

	print_test("Resto 3 frecuencia palabra correcta con frecuencia 6 = true" ,restar_frecuencia(unapalabra,3*unidad) == true);
	print_test("Obtener frecuencia palabra correcta luego de disminuir frecuencia a 0 = 0" ,obtener_frecuencia(unapalabra) == 3);

	print_test("Resto 4 frecuencia palabra correcta con frecuencia 3 = true" ,restar_frecuencia(unapalabra,3*unidad) == true);
	print_test("Obtener frecuencia palabra correcta luego de disminuir frecuencia a -1 = 0" ,obtener_frecuencia(unapalabra) == 0);


	palabra_destruir(unapalabra);
	
	//prueba aumentar la frecuencia al limite 
	palabra_t* otrapalabra = palabra_crear("palabra");
	
	int indice;
	bool control;
	control = true;
	for(indice=1; indice< tope; indice++)
	{
		sumar_frecuencia(otrapalabra);
		if ( obtener_frecuencia(otrapalabra) != (indice +1) )
			control = false;
	}
	if (control){
		print_test("Probar frecuencia al limite (65535)" ,0 == 0);
	}else{
		print_test("Probar frecuencia al limite (65535)" ,0 == 1);
	}
	
	//pruebo decrementar la frecuencia desde el limite
	control = true;
	for(indice=tope; indice > 0; indice--)
	{
		restar_frecuencia(otrapalabra,unidad);
		if ( obtener_frecuencia(otrapalabra) != (indice-1) )
			control = false;
	}
	
	if (control){
		print_test("Probar decrementar frecuencia desde el limite(65535) a 0" ,0 == 0);
	}else{
		print_test("Probar decrementar frecuencia desde el limite(65535) a 0" ,0 == 1);
	}
	
	palabra_destruir(otrapalabra);
}

void prueba_crear_contexto_vacio()
{
	contexto_t* unContexto = ctx_crear(NULL);
	char *unaPalabra = "unapalabra";
	unsigned short unValor=5;
	
	print_test("Crear contexto nulo = vacio",unContexto == NULL);
	print_test("Insertar valor en contexto nulo = false" ,ctx_ingresar_palabra(unContexto,unaPalabra) == false);
	print_test("Borrar frecuencia palabra en contexto nulo  = false" ,ctx_borrar_frecuencia(unContexto,unaPalabra,unValor) == false);
	print_test("Obtener frecuencia palabra en contexto nulo = false" ,ctx_obtener_frecuencia(unContexto,unaPalabra) == 0);
	print_test("Obtener valor en contexto nulo = NULL" ,ctx_obtener_valor(unContexto) == NULL);
	print_test("Obtener apariciones de contexto nulo = 0" ,	ctx_obtener_apariciones(unContexto) == 0);
	

	unContexto = ctx_crear("");
	print_test("Crear contexto vacio = nulo",unContexto == NULL);
	print_test("Insertar valor en contexto vacio =false " ,ctx_ingresar_palabra(unContexto,unaPalabra) == false);
	print_test("Borrar frecuencia palabra en contexto vacio "" = false" ,ctx_borrar_frecuencia(unContexto,unaPalabra,unValor) == false);
	print_test("obtener frecuencia palabra en contexto vacio = false" ,ctx_obtener_frecuencia(unContexto,unaPalabra) == 0);
	print_test("Obtener valor en contexto vacio = NULL" ,ctx_obtener_valor(unContexto) == NULL);
	print_test("Obtener apariciones de contexto vacio = 0" ,	ctx_obtener_apariciones(unContexto) == 0);

	
	print_test("Insertar valor nulo en contexto nulo = false" ,ctx_ingresar_palabra(NULL,NULL) == false);
	print_test("Insertar valor vacio en contexto nulo = false" ,ctx_ingresar_palabra(NULL,"") == false);
	print_test("Borrar frecuencia palabra nula en contexto nulo  = false" ,ctx_borrar_frecuencia(NULL,NULL,unValor) == false);
	print_test("obtener frecuencia palabra NULA en contexto nulo = false" ,ctx_obtener_frecuencia(NULL,NULL) == 0);
	
}
void prueba_crear_contexto_correcto()
{
	char *palabra1 = "unapalabra";
	char *palabra2 = "otra palabra";
	contexto_t* unContexto= ctx_crear(palabra1); ;
	unsigned short unValor=1;
	
	print_test("Crear contexto correcto no es vacio",unContexto != NULL);
	print_test("Insertar valor nulo en contexto correcto = false" ,ctx_ingresar_palabra(unContexto,NULL) == false);
	print_test("Insertar valor vacio en contexto correcto = false" ,ctx_ingresar_palabra(unContexto,"") == false);
	print_test("Borrar frecuencia palabra nula en contexto correcto  = false" ,ctx_borrar_frecuencia(unContexto,NULL,unValor) == false);
	print_test("obtener frecuencia palabra NULA en contexto correcto = false" ,ctx_obtener_frecuencia(unContexto,NULL) == 0);
	print_test("Obtener valor en contexto correcto != NULL" ,ctx_obtener_valor(unContexto) != NULL);
	print_test("Obtener valor en contexto correcto no es puntero creado" ,ctx_obtener_valor(unContexto) != palabra1);
	print_test("Obtener valor en contexto correcto contiene el mismo valor que el puntero con el que se creo" ,strcmp(ctx_obtener_valor(unContexto),palabra1) ==0);
	print_test("Obtener apariciones de contexto correcto nuevo = 0" ,	ctx_obtener_apariciones(unContexto) == 0);

	print_test("Insertar valor1 en contexto correcto = true" ,ctx_ingresar_palabra(unContexto,palabra1) == true);
	print_test("Obtener frecuencia valor1 en contexto correcto = 1" ,ctx_obtener_frecuencia(unContexto,palabra1) == 1);
	print_test("Obtener apariciones de contexto correcto = 1" ,	ctx_obtener_apariciones(unContexto) == 1*unidad);

	print_test("Insertar valor1 en contexto correcto = true" ,ctx_ingresar_palabra(unContexto,palabra1) == true);
	print_test("Obtener frecuencia valor1 en contexto correcto = 2" ,ctx_obtener_frecuencia(unContexto,palabra1) == 2);
	print_test("Obtener apariciones de contexto correcto = 2" ,	ctx_obtener_apariciones(unContexto) == 2*unidad);

	print_test("Obtener frecuencia valor2 en contexto correcto = 0" ,ctx_obtener_frecuencia(unContexto,palabra2) == 0);
				
	print_test("Borrar frecuencia palabra1 correcta en contexto correcto  = true" ,ctx_borrar_frecuencia(unContexto,palabra1,unValor) == true);
	print_test("obtener frecuencia palabra1 correcta en contexto correcto = 1" ,ctx_obtener_frecuencia(unContexto,palabra1) == 1);

	print_test("Borrar frecuencia de palabra1 correcta confre en contexto correcto  = true" ,ctx_borrar_frecuencia(unContexto,palabra1,unValor) == true);
	print_test("obtener frecuencia palabra1 correcta en contexto correcto = 0" ,ctx_obtener_frecuencia(unContexto,palabra1) == 0);

	print_test("Borrar frecuencia de palabra1 correcta con frecuencia 0 en contexto correcto  = false" ,ctx_borrar_frecuencia(unContexto,palabra1,unValor) == false);
	print_test("obtener frecuencia palabra1 correcta en contexto correcto   = 0" ,ctx_obtener_frecuencia(unContexto,palabra1) == 0);
	
	print_test("Obtener frecuencia valor2 en contexto correcto = 0" ,ctx_obtener_frecuencia(unContexto,palabra2) == 0);
	print_test("Borrar frecuencia de palabra que no exite en contexto correcto  = false" ,ctx_borrar_frecuencia(unContexto,palabra2,unValor) == false);
	print_test("Obtener frecuencia valor2 en contexto correcto = 0" ,ctx_obtener_frecuencia(unContexto,palabra2) == 0);


	ctx_destruir(unContexto);
}
void prueba_crear_palabras_en_contexto_en_volumen(size_t cantidad){
	char* palabra1 = "unaPalabra";
	int indice;
	bool fallo = false;
	
	contexto_t* unContexto = ctx_crear(palabra1);
	print_test("Crear contexto correcto en pruebas volumen != null" ,unContexto != NULL);

	//inicializacion para la funcion rand_str
	char mytext[10];
	srand(time(0));

	//agrego cantidad de palabras de tamaño max 10 al contexto, elegidas al azar.
	//puede ser que se agregue mas de una palabra a un contexto
	for ( indice = 0; indice < cantidad; indice++ )
	{
	  char* cadena = rand_str(mytext, sizeof mytext);
	  if (strcmp(cadena, "")!=0){
		  bool control = ctx_ingresar_palabra(unContexto,cadena);
		  if (! control)
			fallo=true;
	  }
		
	}
	if (fallo){
		print_test("Crear palabras en volumen en contexto correcto" ,0 == 1);
	}else{
		print_test("Crear palabras en volumen en contexto correcto" ,0 == 0);	
	}
	ctx_destruir(unContexto);
}
void prueba_crear_contenedor_contexto_vacio(){
	ctdctx_t* unContenedor = ctdctx_crear(0);
	char *unaPalabra = "unapalabra";
	
	print_test("Crear contenedor vacio != nulo",unContenedor != NULL);
	print_test("Insertar valor nulo en contexto correcto en contexto una palabra = false" ,ctdctx_ingresar_palabra(unContenedor,unaPalabra,NULL) == false);
	print_test("Insertar valor vacio en contexto correcto en contexto una palabra = false" ,ctdctx_ingresar_palabra(unContenedor,unaPalabra,"") == false);
	print_test("Insertar valor correcto en contexto nulo en contexto una palabra = false" ,ctdctx_ingresar_palabra(unContenedor,NULL,unaPalabra) == false);
	print_test("Insertar valor correcto en contexto vacio en contexto una palabra = false" ,ctdctx_ingresar_palabra(unContenedor,"",unaPalabra) == false);
	print_test("Insertar valor correcto en contexto correcto en contenedor NULL = false" ,ctdctx_ingresar_palabra(NULL,unaPalabra,unaPalabra) == false);


	print_test("Obtener cantidad de palabras en contexto nulo = 0" ,ctdctx_cantidad(NULL) == 0);
	print_test("Obtener cantidad de palabras en contexto vacio = 0" ,ctdctx_cantidad(unContenedor) == 0);
	
	ctdctx_destruir(unContenedor);
}
void prueba_crear_contenedor_contexto_correcto()
{
	char *palabra1 = "unapalabra";
	char *palabra2 = "otra palabra";
	char *palabra3 = "palabra3";
	
	ctdctx_t* unContenedor = ctdctx_crear(0);
	
	print_test("Crear contenedor correcto no es vacio",unContenedor != NULL);
	print_test("Obtener cantidad de palabras en contexto vacio = 0" ,ctdctx_cantidad(unContenedor) == 0*unidad);

	print_test("Insertar valor correcto en contexto nuevo correcto = true", ctdctx_ingresar_palabra(unContenedor,palabra1,palabra2)  == true);
	print_test("Obtener cantidad de palabras en contexto nuevo = 2" ,ctdctx_cantidad(unContenedor) == 2*unidad);

	//inserto nuevamente en contexto ya creado
	print_test("Insertar valor correcto en contexto ya creado = true", ctdctx_ingresar_palabra(unContenedor,palabra1,palabra2) == true);
	print_test("Obtener cantidad de palabras en contexto vacio = 3" ,ctdctx_cantidad(unContenedor) == 3*unidad);

	//inserto nuevamente en contexto nuevo
	print_test("Insertar valor correcto en contexto nuevo correcto = true", ctdctx_ingresar_palabra(unContenedor,palabra2,palabra1)  == true);
	print_test("Obtener cantidad de palabras en contextos  = 5" ,ctdctx_cantidad(unContenedor) == 5*unidad);

	print_test("Insertar valor correcto en contexto ya creado = true", ctdctx_ingresar_palabra(unContenedor,palabra2,palabra1) == true);
	print_test("Obtener cantidad de palabras en contextos = 6" ,ctdctx_cantidad(unContenedor) == 6*unidad);

	//agrego una palabra diferente al contexto ya creado y con un unico valor
	print_test("Insertar otro valor diferente correcto en contexto ya creado = true", ctdctx_ingresar_palabra(unContenedor,palabra2,palabra3) == true);
	print_test("Obtener cantidad de palabras en contextos = 7" ,ctdctx_cantidad(unContenedor) == 7*unidad);

	ctdctx_destruir(unContenedor);

}
void prueba_crear_contextos_en_contenedor_en_volumen(size_t cantidad){
	char* unContexto;
	char* unaPalabra;
	int indice;
	bool fallo = false;
	
	ctdctx_t* unContenedor = ctdctx_crear(0);
	print_test("Crear contenedor correcto en pruebas volumen != null" ,unContenedor != NULL);

	//inicializacion para la funcion rand_str
	char mytext[10];
	srand(time(0));

	//agrego cantidad de contextos de tamaño max 10 al contenedor, elegidas al azar.
	//puede darse el caso de que se agregue mas de una palabra a un contexto
	for ( indice = 0; indice < cantidad; indice++ )
	{
	  unContexto = rand_str(mytext, sizeof mytext);
	  unaPalabra = rand_str(mytext, sizeof mytext);
	  if ( (strcmp(unaPalabra, "")!=0) || (strcmp(unContexto, "")!=0)){
		  bool control = ctdctx_ingresar_palabra(unContenedor,unContexto,unaPalabra);
		  if (! control)
			fallo=true;
	  }
		
	}
	if (fallo){
		print_test("Crear contextos en volumen en contenedor correcto" ,0 == 1);
	}else{
		print_test("Crear contextos en volumen en contenedor correcto" ,0 == 0);	
	}
	ctdctx_destruir(unContenedor);
}
void prueba_crear_contextos_y_palabras_en_contenedor_en_volumen(size_t cantCont,size_t CantPal){
	char* unContexto;
	char* unaPalabra;
	int indiceCon;
	int indicePal;
	bool fallo = false;
		
	ctdctx_t* unContenedor = ctdctx_crear(0);
	print_test("Crear contenedor correcto en pruebas volumen != null" ,unContenedor != NULL);

	//inicializacion para la funcion rand_str
	char mytext[10];
	srand(time(0));

	//agrego cantidad de contextos de tamaño max 10 al contenedor, elegidas al azar.
	//puede darse el caso de que se agregue mas de una palabra a un contexto
	for ( indiceCon = 0; indiceCon < cantCont; indiceCon++ )
	{
		unContexto = rand_str(mytext, sizeof mytext);
		if ( strcmp(unContexto, "")!=0 ){
		
			for ( indicePal = 0; indicePal < CantPal; indicePal++ )
			{
			  unaPalabra = rand_str(mytext, sizeof mytext);
			  if ( strcmp(unaPalabra, "")!=0){
				  bool control = ctdctx_ingresar_palabra(unContenedor,unContexto,unaPalabra);
				  if (! control)
					fallo=true;
			  }		
			}
		}
	}
	if (fallo){
		print_test("Crear palabras y contextos en volumen en contenedor correcto" ,0 == 1);
	}else{
		print_test("Crear palabras y contextos en volumen en contenedor correcto" ,0 == 0);	
	}
	ctdctx_destruir(unContenedor);
}
void prueba_decodificar(){
	ctdctx_t* unContenedor = ctdctx_crear(0);
	if (!unContenedor)
		return;
	int indice;
	
	for (indice = 0; indice < 999; indice++){
		ctdctx_ingresar_palabra(unContenedor,"san","francisco");
		ctdctx_ingresar_palabra(unContenedor,"francisco","san");
		ctdctx_ingresar_palabra(unContenedor,"infomation","tecnology");
		ctdctx_ingresar_palabra(unContenedor,"tecnology","infomation");
	}
	for (indice = 0; indice < 2; indice++){
		ctdctx_ingresar_palabra(unContenedor,"san","patricks");
		ctdctx_ingresar_palabra(unContenedor,"francisco","bridge");
		ctdctx_ingresar_palabra(unContenedor,"infomation","devices");
		ctdctx_ingresar_palabra(unContenedor,"tecnology","age");
	}

	printf("\n Prueba extraer terminos, cantidad de terminos = %d:\n",ctdctx_cantidad(unContenedor));	
	printf("Resultado de extraer terminos en parser: Ver archivo .temp generado\n");	
	ctdctx_decodificar(unContenedor);
	ctdctx_destruir(unContenedor);

}
/* ******************************************************************
 *                        PROGRAMA PRINCIPAL
 * *****************************************************************/


/* Programa principal. */
int main(void)
{

/*	prueba_crear_palabra_vacio();
	prueba_crear_palabra_correcta();
	prueba_crear_contexto_vacio();
	prueba_crear_contexto_correcto();
	prueba_crear_palabras_en_contexto_en_volumen(10000);	
	prueba_crear_contenedor_contexto_vacio();
	prueba_crear_contenedor_contexto_correcto();
	prueba_crear_contextos_en_contenedor_en_volumen(10000);
	prueba_crear_contextos_y_palabras_en_contenedor_en_volumen(1000,100);
*/
	prueba_decodificar();
    return 0;
}
